#include "st7735.h"
#include "wk_system.h"
#include "at32f403a_407_wk_config.h"
#include "lcdfont.h"
#include "stdarg.h"
#include "wk_dma.h"

volatile uint32_t LCD_RAM_UPDATE = 1;
volatile uint32_t LCD_RAM_DMA_TRANSFER = 0;
uint16_t LCDBUFF[LCD_RAM_W * LCD_RAM_H] = {[0 ... (LCD_RAM_W * LCD_RAM_H - 1) ] = BACK_COLOR};


void LCD_Fill(uint8_t xsta,uint8_t ysta,uint8_t xend,uint8_t yend,uint16_t color);
void LCD_DrawLine(u8 x1,u8 y1,u8 x2,u8 y2,u16 color);
void buff_flush(void);

__attribute__((noinline)) static void LCD_Writ_Bus(u8 dat) 
{
    while(spi_i2s_flag_get(SPI2, SPI_I2S_TDBE_FLAG) == RESET);
	spi_i2s_data_transmit(SPI2, dat);
}

void LCD_WR_DATAS(uint8_t* buff, size_t buff_size)
{
    OLED_DC_Set();//
    for(int i=0; i<buff_size; i++)
    {
        LCD_Writ_Bus(buff[i]);
    }
}

void LCD_WR_DATA8(u8 dat)		//
{
    OLED_DC_Set();//
	LCD_Writ_Bus(dat);
}

void LCD_WR_DATA16(u16 dat)	       //
{
	LCD_Writ_Bus(dat>>8);
	LCD_Writ_Bus(dat);
}

void LCD_WR_REG(u8 dat)			//
{
	OLED_DC_Clr();//
	LCD_Writ_Bus(dat);
}

void LCD_Address_Set(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1)
{
    LCD_WR_REG(0x2A);
    LCD_WR_DATA8(0x00);
    LCD_WR_DATA8(x0);
    LCD_WR_DATA8(0x00);
    LCD_WR_DATA8(x1);

    LCD_WR_REG(0x2B);
    LCD_WR_DATA8(0x00);
    LCD_WR_DATA8(y0);
    LCD_WR_DATA8(0x00);
    LCD_WR_DATA8(y1);
    
    LCD_WR_REG(0x2C);
}

void ST7735_Init(void)
{
    wk_spi2_init();
    LCD_Writ_Bus(0xFF);
    gpio_bits_reset(TFT_CS_GPIO_PORT, TFT_CS_PIN);
	gpio_bits_set(TFT_RST_GPIO_PORT, TFT_RST_PIN);
	delay_ms(50);
    
    LCD_WR_REG(0x11);//Sleep exit 
	delay_ms (120);
	LCD_WR_REG(0x21); 
    LCD_WR_REG(0x21); 

    LCD_WR_REG(0xB1); 
    LCD_WR_DATA8(0x05);
    LCD_WR_DATA8(0x3A);
    LCD_WR_DATA8(0x3A);

    LCD_WR_REG(0xB2);
    LCD_WR_DATA8(0x05);
    LCD_WR_DATA8(0x3A);
    LCD_WR_DATA8(0x3A);

    LCD_WR_REG(0xB3); 
    LCD_WR_DATA8(0x05);  
    LCD_WR_DATA8(0x3A);
    LCD_WR_DATA8(0x3A);
    LCD_WR_DATA8(0x05);
    LCD_WR_DATA8(0x3A);
    LCD_WR_DATA8(0x3A);

    LCD_WR_REG(0xB4);
    LCD_WR_DATA8(0x03);

    LCD_WR_REG(0xC0);
    LCD_WR_DATA8(0x62);
    LCD_WR_DATA8(0x02);
    LCD_WR_DATA8(0x04);

    LCD_WR_REG(0xC1);
    LCD_WR_DATA8(0xC0);

    LCD_WR_REG(0xC2);
    LCD_WR_DATA8(0x0D);
    LCD_WR_DATA8(0x00);

    LCD_WR_REG(0xC3);
    LCD_WR_DATA8(0x8D);
    LCD_WR_DATA8(0x6A);   

    LCD_WR_REG(0xC4);
    LCD_WR_DATA8(0x8D); 
    LCD_WR_DATA8(0xEE); 

    LCD_WR_REG(0xC5);  /*VCOM*/
    LCD_WR_DATA8(0x0E);    

    LCD_WR_REG(0xE0);
    LCD_WR_DATA8(0x10);
    LCD_WR_DATA8(0x0E);
    LCD_WR_DATA8(0x02);
    LCD_WR_DATA8(0x03);
    LCD_WR_DATA8(0x0E);
    LCD_WR_DATA8(0x07);
    LCD_WR_DATA8(0x02);
    LCD_WR_DATA8(0x07);
    LCD_WR_DATA8(0x0A);
    LCD_WR_DATA8(0x12);
    LCD_WR_DATA8(0x27);
    LCD_WR_DATA8(0x37);
    LCD_WR_DATA8(0x00);
    LCD_WR_DATA8(0x0D);
    LCD_WR_DATA8(0x0E);
    LCD_WR_DATA8(0x10);

    LCD_WR_REG(0xE1);
    LCD_WR_DATA8(0x10);
    LCD_WR_DATA8(0x0E);
    LCD_WR_DATA8(0x03);
    LCD_WR_DATA8(0x03);
    LCD_WR_DATA8(0x0F);
    LCD_WR_DATA8(0x06);
    LCD_WR_DATA8(0x02);
    LCD_WR_DATA8(0x08);
    LCD_WR_DATA8(0x0A);
    LCD_WR_DATA8(0x13);
    LCD_WR_DATA8(0x26);
    LCD_WR_DATA8(0x36);
    LCD_WR_DATA8(0x00);
    LCD_WR_DATA8(0x0D);
    LCD_WR_DATA8(0x0E);
    LCD_WR_DATA8(0x10);

    LCD_WR_REG(0x3A); 
    LCD_WR_DATA8(0x05);

    LCD_WR_REG(0x36);
    LCD_WR_DATA8(0x08);//

    LCD_WR_REG(0x29); 
    
    delay_ms(5);
    
    LCD_Address_Set(0,0,LCD_RAM_W-1,LCD_RAM_H-1);
    delay_ms(1);
	
    SPI2->ctrl1_bit.mdiv_l = SPI_MCLK_DIV_2;    // 提高传输速率
    
    OLED_DC_Set();//
    
    // LCD_Clear(WHITE);
    
    // LCD_Fill(0,0,79,79,BLUE);
    //LCD_Fill(50,50,100,79,ST7735_WHITE);
    
    // buff_flush();
    // oledString(0,0,A2012,ST7735_RED,"5241325423");
    
    // LCD_DrawLine(10,10,50,50,ST7735_WHITE);
    
    // buff_flush();
    // buff_dma_flush();
    
    
    
}


void LCD_Clear(uint16_t Color)	//LCD
{
	LCD_Address_Set(0,0,LCD_RAM_W-1,LCD_RAM_H-1);
    delay_ms(1);
	OLED_DC_Set();//д����
	for(int i=0;i<LCD_RAM_H;i++)
	{
		for(int j=0;j<LCD_RAM_W;j++)
		{
			LCD_WR_DATA16(Color);
		}
	}
}


void buff_flush(void)
{
	LCD_Address_Set(0,0,LCD_RAM_W-1,LCD_RAM_H-1);
    LCD_WR_REG(0x2C);
    delay_ms(1);
	OLED_DC_Set();//
	for(int i=0;i<LCD_RAM_H;i++)
	{
		for(int j=0;j<LCD_RAM_W;j++)
		{
			LCD_WR_DATA16(LCDBUFF[i*LCD_RAM_W + j]);
		}
	}
}




void buff_dma_flush(void)
{
    uint8_t chen = DMA2_CHANNEL1->ctrl;
    
    if(LCD_RAM_UPDATE !=0 && ( (chen & 0x01) == 0) && LCD_RAM_DMA_TRANSFER == 0)
    {
        LCD_RAM_UPDATE = 0;
        // LCD_Address_Set(0,0,LCD_W-1,LCD_H-1);
        // __NOP();__NOP();__NOP();__NOP();__NOP();
        // OLED_DC_Set();//
        dma_data_number_set(DMA2_CHANNEL1, sizeof(LCDBUFF));
        LCD_RAM_DMA_TRANSFER = 1;
        dma_channel_enable(DMA2_CHANNEL1, TRUE);
        // log("buff_dma_flush \r\n");
    }
}



static inline void LCD_DrawPoint(uint32_t x, uint32_t y, uint16_t color)	//打点,坐标
{
    if(x> LCD_RAM_H-1 || y>LCD_RAM_W-1)	return ;
    LCDBUFF[(160-x) * LCD_RAM_W + (26+y)] = color;
}



void LCD_Fill(uint8_t xsta,uint8_t ysta,uint8_t xend,uint8_t yend, uint16_t color)	//在指定区域填充颜色，起始坐标，终止坐标
{          
	uint8_t i,j;
	if(ysta>yend && xsta>xend)	{i=yend; yend=ysta; ysta=i; i=xend; xend=xsta; xsta=i;}
	else if(ysta>yend)	{i=yend; yend=ysta; ysta=i;}
	else if(xsta>xend)	{i=xend; xend=xsta; xsta=i;}
	//LCD_Address_Set(xsta,ysta,xend,yend);      	//
	for(i=ysta;i<=yend;i++)
	{
		for(j=xsta;j<=xend;j++)
		{
			// LCDBUFF[i*240+j] = color;	//
            LCD_DrawPoint(j,i,color);	//
		}
	}
}



void LcdFillScreen(uint8_t dat, uint16_t color) 
{
	uint8_t  i,j;
	for(i=0;i<8;i++)
	{
		for(j=0;j<128;j++)
		{
            LCD_DrawPoint(j,i,color);	//
		}
	}
}

 
void LcdClearScreen(void) 
{
	LcdFillScreen(0x00, WHITE);
}


//从字库中查找出字模
uint8_t *Get_HzMat(uint16_t code, uint16_t mode)
{
    uint16_t volatile *pHZ;
    
    if(mode & G2424)
    {
        pHZ = (uint16_t *)HZ_2424;
        for(int i=0; i< sizeof(HZ_code_2424)/sizeof(HZ_code_2424[0]) ; i++)
        {
            if(code == pHZ[i])
            {
                return (uint8_t *)HZ_code_2424[i];
            }
        }
    }else if(mode & G2020)
    {
        pHZ = (uint16_t *)HZ_2020;
        for(int i=0; i< sizeof(HZ_code_2020)/sizeof(HZ_code_2020[0]) ; i++)
        {
            if(code == pHZ[i])
            {
                return (uint8_t *)HZ_code_2020[i];
            }
        }
    }else{
        pHZ = (uint16_t *)HZ;
        for(int i=0; i< sizeof(HZ_code)/sizeof(HZ_code[0]) ; i++)
        {
            if(code == pHZ[i])
            {
                return (uint8_t *)HZ_code[i];
            }
        }
    }
    return NULL;
}

void TFT_ShowChar(uint8_t x1,uint8_t y1,uint8_t x2,uint8_t y2,uint8_t *font,uint16_t mode,uint16_t color)    //显示字符,起点坐标,要显示的字符
{
    uint8_t temp;
	uint32_t t,i=0;
	uint32_t x = x1;
	uint16_t COLOR1,COLOR2;
    
    if(font == NULL) return ;
	if(mode&REVERSE)	{COLOR1 = BACK_COLOR;	COLOR2 = color;}	//反白显示
	else	{COLOR1 = color;	COLOR2 = BACK_COLOR;}		        //非反白显示
	// if(mode & OVERLAY)		//叠加显示
    for(; y1<y2; y1++)
    {
        for(; x1<x2; x1+=8)
        {
            temp = font[i];
            for(t=0;t<8;t++)
            {
                if(temp&0x01)	LCD_DrawPoint(x1+t, y1, COLOR1);
                else LCD_DrawPoint(x1+t, y1, COLOR2);	//背景
                temp >>=1;
            }
            i++;
        }
        x1 = x;
    }
}

void oledString(uint8_t x, uint8_t y, uint16_t mode, uint16_t color, const char  *str)        //显示字
{
    uint32_t chr;
    uint8_t *font;
    unsigned char *pstr = (unsigned char *)str;
    if(y > 79 || x > 159 || str == NULL)  return;
    
    while(*pstr != '\0')
    {
        if(*pstr < 0x80)                                  //ASCII
        {
            if(x > (160 - 8))
            {
                if((mode & NEWLINE) && (y < (8 - 2)))
                {
                    y += 2;
                    x = 0;
                }else break;
            }
            chr = *pstr - ' ';
            if(mode & A2416)
            {
                TFT_ShowChar(x,y,x+16,y+24,(uint8_t *)ascii_2416[chr],mode,color);
                x += 16;
            }else if(mode & A2012){
                TFT_ShowChar(x,y,x+12,y+20,(uint8_t *)ascii_2012[chr],mode,color);
                x += 12;
            }else{
                TFT_ShowChar(x,y,x+8,y+16,(uint8_t *)ascii_1608[chr],mode,color);
                x += 8;
            }
            pstr++;
        }else{
            if(x > (159 - 16))
            {
                if((mode & NEWLINE) && (y < (8 - 2)))
                {
                    y += 2;
                    x = 0;
                }else break;
            }
            chr = ((*(pstr+1))<<8) + (*pstr);
            font = Get_HzMat(chr, mode);
            if(mode & G2424)
            {
                TFT_ShowChar(x,y,x+24,y+24,font,mode,color);
                pstr += 2;
                x += 24;
            }else if(mode & G2020)
            {
                TFT_ShowChar(x,y,x+20,y+20,font,mode,color);
                pstr += 2;
                x += 20;
            }else{
                TFT_ShowChar(x,y,x+16,y+16,font,mode,color);
                pstr += 2;
                x += 16;
            }
        }
        if(mode & ENTIRE)													//占用一整行
		{
			if(*pstr == '\0')
			{
				mode &= ~NEWLINE;
				pstr = (unsigned char *)" ";
			}
		}
    }
    LCD_RAM_UPDATE = 1;
    buff_dma_flush();
}


void oledPrintf(uint8_t x,uint8_t y, uint16_t mode, uint16_t color, char *p,... )
{
    char buf[72];
    va_list ap;
    va_start(ap,p);
    vsprintf(buf,p,ap);
    va_end(ap);
    oledString(x,y,mode,color,buf);
}


void lcd_dma_clear_color(uint16_t color)
{
    dma_init_type dma_init_struct = {0};
    static uint32_t color_dma;
    
    color_dma = (uint32_t)color << 16 | color;
    
    dma_reset(DMA2_CHANNEL2);
    dma_init_struct.buffer_size = sizeof(LCDBUFF)/4;
    dma_init_struct.direction = DMA_DIR_MEMORY_TO_MEMORY;
    dma_init_struct.memory_base_addr = (uint32_t)&LCDBUFF;
    dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_WORD;
    dma_init_struct.memory_inc_enable = TRUE;
    dma_init_struct.peripheral_base_addr = (uint32_t)&color_dma;
    dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_WORD;
    dma_init_struct.peripheral_inc_enable = FALSE;
    dma_init_struct.priority = DMA_PRIORITY_VERY_HIGH;
    dma_init_struct.loop_mode_enable = FALSE;
    dma_init(DMA2_CHANNEL2, &dma_init_struct);
    
    dma_channel_enable(DMA2_CHANNEL2, TRUE);
}

void lcd_dma_clear_background_color(void)
{
    lcd_dma_clear_color(BACK_COLOR);
}


void wk_dma2_channel1_init(void)
{
    dma_init_type dma_init_struct;
    
    dma_reset(DMA2_CHANNEL1);
    dma_default_para_init(&dma_init_struct);
    dma_init_struct.buffer_size = sizeof(LCDBUFF);
    dma_init_struct.direction = DMA_DIR_MEMORY_TO_PERIPHERAL;
    dma_init_struct.memory_base_addr = (uint32_t)LCDBUFF;
    dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_BYTE;
    dma_init_struct.memory_inc_enable = TRUE;
    dma_init_struct.peripheral_base_addr = (uint32_t)&(SPI2->dt);
    dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_BYTE;
    dma_init_struct.peripheral_inc_enable = FALSE;
    dma_init_struct.priority = DMA_PRIORITY_MEDIUM;
    dma_init_struct.loop_mode_enable = FALSE;
    dma_init(DMA2_CHANNEL1, &dma_init_struct);
    
    dma_flag_clear(DMA2_FDT1_FLAG);
    dma_interrupt_enable(DMA2_CHANNEL1, DMA_FDT_INT, TRUE);
    
    dma_flexible_config(DMA2, FLEX_CHANNEL1, DMA_FLEXIBLE_SPI2_TX);
    
    dma_channel_enable(DMA2_CHANNEL1, FALSE);
}


void wk_spi2_init(void)
{
    gpio_init_type gpio_init_struct;
    spi_init_type spi_init_struct;

    gpio_default_para_init(&gpio_init_struct);
    spi_default_para_init(&spi_init_struct);

    /* configure the SCK pin */
    gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
    gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
    gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
    gpio_init_struct.gpio_pins = GPIO_PINS_13;
    gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
    gpio_init(GPIOB, &gpio_init_struct);

    /* configure the MOSI pin */
    gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
    gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
    gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
    gpio_init_struct.gpio_pins = GPIO_PINS_15;
    gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
    gpio_init(GPIOB, &gpio_init_struct);
    
    /* configure param */
    spi_init_struct.transmission_mode = SPI_TRANSMIT_HALF_DUPLEX_TX;
    spi_init_struct.master_slave_mode = SPI_MODE_MASTER;
    spi_init_struct.frame_bit_num = SPI_FRAME_8BIT;
    spi_init_struct.first_bit_transmission = SPI_FIRST_BIT_MSB;
    spi_init_struct.mclk_freq_division = SPI_MCLK_DIV_32;
    spi_init_struct.clock_polarity = SPI_CLOCK_POLARITY_HIGH;
    spi_init_struct.clock_phase = SPI_CLOCK_PHASE_1EDGE;
    spi_init_struct.cs_mode_selection = SPI_CS_SOFTWARE_MODE;
    spi_init(SPI2, &spi_init_struct);
    
    spi_enable(SPI2, TRUE);
    spi_i2s_dma_transmitter_enable(SPI2, TRUE);
    
    wk_dma2_channel1_init();
}



